package com.poka.device;

import android.util.Log;

import com.android.hdhe.uhf.reader.SerialPort;
import com.china_isi.crypto.SM4Utils;
import com.poka_global_constant.Util;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class RFIDDevice {

    private static final String TAG = "RFIDDevice";
    private static RFIDDevice rfid_device;
    private OnDataReceiveListener onDataReceiveListener = null;

    private ReadThread mReadThread;

    private SerialPort rfidSerialPort;

    private OutputStream mOutputStream;

    private InputStream mInputStream;
    private static final String tag = "RFIDDevice";
    private boolean isStop = false;

    public RFIDDevice() {
        initRFID();
    }

    public static RFIDDevice getInstance() {
        if (null == rfid_device) {
            rfid_device = new RFIDDevice();
        }
        return rfid_device;
    }

    public void setOnDataReceiveListener(OnDataReceiveListener dataReceiveListener) {
        this.onDataReceiveListener = dataReceiveListener;
    }

    public boolean sendBuffer(byte[] mBuffer) {
        boolean result = true;
        String tail = "";
        byte[] tailBuffer = tail.getBytes();
        byte[] mBufferTemp = new byte[mBuffer.length + tailBuffer.length];
        System.arraycopy(mBuffer, 0, mBufferTemp, 0, mBuffer.length);
        System.arraycopy(tailBuffer, 0, mBufferTemp, mBuffer.length, tailBuffer.length);
        try {
            if (this.mOutputStream != null) {
                this.mOutputStream.write(mBufferTemp);
            } else {
                result = false;
            }
        } catch (IOException e) {
            e.printStackTrace();
            result = false;
        }
        return result;
    }

    private class ReadThread extends Thread {
        private ReadThread() {
        }

        public void run() {
            super.run();
            while ((!RFIDDevice.this.isStop) && (!isInterrupted())) {
                try {
                    if (RFIDDevice.this.mInputStream == null)
                        return;
                    byte[] buffer = new byte[512];
                    int size = RFIDDevice.this.mInputStream.read(buffer);
//                    System.out.print("buffer" + buffer);
//                    Log.e(TAG, "RFIDD buffer==" + buffer.length);

                    if ((size > 0) &&
                            (null != RFIDDevice.this.onDataReceiveListener)) {
                        RFIDDevice.this.onDataReceiveListener.onDataReceive(buffer, size);
                    }

                    Thread.sleep(1L);
                } catch (Exception e) {
                    e.printStackTrace();
                    return;
                }
            }
        }
    }

    public void closeRFID() {
        this.isStop = true;
        if (this.mReadThread != null) {
            this.mReadThread.interrupt();
        }

        if (this.rfidSerialPort != null) {
            this.rfidSerialPort.psampoweroff();
            this.rfidSerialPort.close(12);
            this.rfidSerialPort = null;
        }

        rfid_device = null;
    }

    private void initRFID() {
        if (this.rfidSerialPort == null) {
            try {
                this.rfidSerialPort = new SerialPort(12, 115200, 0);
            } catch (Exception e) {
                return;
            }
            this.rfidSerialPort.psampoweron();
            this.mOutputStream = this.rfidSerialPort.getOutputStream();
            this.mInputStream = this.rfidSerialPort.getInputStream();
        }
        this.mReadThread = new ReadThread();
        this.isStop = false;
        this.mReadThread.start();
    }

    public SerialPort getRfidSerialPort() {
        return this.rfidSerialPort;
    }

    public void setRfidSerialPort(SerialPort rfidSerialPort) {
        this.rfidSerialPort = rfidSerialPort;
    }

    public boolean searchEPC() {
        String searchCommand = "BB00220000227E";
        byte[] command = Util.hexStr2Bytes(searchCommand);
        sendBuffer(command);
        try {
            Thread.sleep(100L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return true;
    }

    public boolean selectEPC(String EPCID) {
        String selectCommand = "BB000C001301000000206000" + EPCID;
        String checksum = checkSum(selectCommand.substring(2));
        selectCommand = selectCommand + checksum;
        selectCommand = selectCommand + "7E";
        byte[] command = Util.hexStr2Bytes(selectCommand);
        sendBuffer(command);
        try {
            Thread.sleep(50L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return true;
    }

    public boolean selectMode() {
        String selectModeCommand = "BB0012000100137E";
        byte[] command = Util.hexStr2Bytes(selectModeCommand);
        sendBuffer(command);
        try {
            Thread.sleep(50L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return true;
    }

    public boolean unSelectMode() {
        String selectModeCommand = "BB0012000101147E";
        byte[] command = Util.hexStr2Bytes(selectModeCommand);
        sendBuffer(command);
        try {
            Thread.sleep(50L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return true;
    }

    public boolean readUserData(int offset, int len) {
        String offSet = Util.paddingZero(Integer.toString(offset / 2, 16), 4);
        String Len = Util.paddingZero(Integer.toString(len / 2, 16), 4);
        String readCommand = "BB003900090000000003" + offSet + Len;
        String checksum = checkSum(readCommand.substring(2));
        readCommand = readCommand + checksum;
        readCommand = readCommand + "7E";
        byte[] command = Util.hexStr2Bytes(readCommand);
        sendBuffer(command);
        try {
            Thread.sleep(300L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return true;
    }

    public boolean writeUserData(int offset, byte[] data, int len) {
        String offSet = Util.paddingZero(Integer.toString(offset / 2, 16), 4);
        String Len = Util.paddingZero(Integer.toString(len / 2, 16), 4);
        String Data = Util.byte2HexStr(data);
        String AP = "00000000";
        String MemBank = "03";
        String PL = Util.paddingZero(Integer.toString((AP.length() + MemBank.length() + offSet.length() + Len.length() + Data.length()) / 2, 16), 2);
        String readCommand = "BB004900" + PL + AP + MemBank + offSet + Len + Data;
        String checksum = checkSum(readCommand.substring(2));
        readCommand = readCommand + checksum;
        readCommand = readCommand + "7E";
        byte[] command = Util.hexStr2Bytes(readCommand);
        sendBuffer(command);
        try {
            Thread.sleep(len < 100 ? 500L : len * 20);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return true;
    }

    public boolean LockOperation(int OperationMode, byte[] cmdParm) {
        String head = "AA";
        String tail = "BB";
        String cmd = "";
        String cmdDataLen = "";
        String cmdData = "";
        SM4Utils sm4 = null;
        byte[] ivec = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

        switch (OperationMode) {
            case 1:
                cmd = "01";
                cmdDataLen = "0000";
                break;
            case 3:
                cmd = "03";

                byte[] lockerkey = {57, 69, 32, -113, 123, 33, 68, -79, 63, 54, -29, -118, -58, -45, -97, -107};

                sm4 = new SM4Utils(lockerkey, ivec);
                byte[] encdata = sm4.sm4_cbc_encrypt(cmdParm, 0, cmdParm.length);
                cmdDataLen = Util.paddingZero(Integer.toString(encdata.length, 16), 4);
                cmdData = Util.byte2HexStr(encdata);
                break;
            case 4:
                cmd = "04";
                cmdData = Util.byte2HexStr(cmdParm);
                cmdDataLen = Util.paddingZero(Integer.toString(cmdParm.length, 16), 4);
                break;
            case 2:
            default:
                return false;
        }

        String Command = head + cmd + cmdDataLen + cmdData;
        String checksum = checkSum(Command.substring(2));
        Command = Command + checksum;
        Command = Command + tail;

        byte[] cmddata = Util.hexStr2Bytes(Command);
        writeUserData(0, cmddata, cmddata.length);
        return true;
    }

    public String getResult(byte[] rfidreply) {
        String Result = Util.byte2HexStr(rfidreply).substring(40);

        return Result;
    }

    public String checkSum(String cmd) {
        String res = "";
        byte[] cmdbyte = Util.hexStr2Bytes(cmd);
        short checksum = 0;
        for (int i = 0; i < cmdbyte.length; i++)
            checksum = (short) (checksum + cmdbyte[i]);
        checksum = (short) (checksum & 0xFF);
        res = Util.paddingZero(Integer.toString(checksum, 16), 4).substring(2);
        return res;
    }

    public static abstract interface OnDataReceiveListener {
        public abstract void onDataReceive(byte[] paramArrayOfByte, int paramInt);
    }
}
